/**
 * phi
 */

// ----------------------------------------------------------------
// 定数
// ----------------------------------------------------------------
var MOVE_SPEED  = 1;
var AUDIO_EXT   = (function(){
    var ext = "";
    var audio = new Audio();
    
    if      (audio.canPlayType("audio/mp3") == 'maybe') { ext="mp3"; }
    else if (audio.canPlayType("audio/ogg") == 'maybe') { ext="ogg"; }
    else if (audio.canPlayType("audio/wav") == 'maybe') { ext="wav"; }
    
    return ext;
})();
var BROWSER = (function(){
    if      (/chrome/i.test(navigator.userAgent))   { return "Chrome";  }
    else if (/safari/i.test(navigator.userAgent))   { return "Safari";  }
    else if (/firefox/i.test(navigator.userAgent))  { return "Firefox"; }
    else if (/opera/i.test(navigator.userAgent))    { return "Opera";   }
    else if (/getcko/i.test(navigator.userAgent))   { return "Getcko";  }
    else if (/msie/i.test(navigator.userAgent))     { return "IE";      }
    else { return null; }
})();

// ----------------------------------------------------------------
// グローバル変数
// ----------------------------------------------------------------
var game            = null;
var light           = null;
var camera          = null;
var floor           = null;
var player          = null;
var shadow          = null;
var nineleapBoxRoot = null;
var score           = null;

// おまじない
enchant();

window.onload = function()
{
    initGame();
};

/**
 * 
 */
var initGame = function()
{
    game = new Game(640, 640);
    game.fps = 60;
    game.keybind(90, 'a');      // z
    game.keybind(88, 'b');      // x
    game.keybind(32, "space");  // space
    
    game.preload("model/marukichi.mqo");
    game.score = 0;
    
    game.onload = function() {
        var scene = new Scene3D();
        scene.backgroundColor = [ 0.0, 0.0, 0.0, 1.0 ];
        
        // ライト生成
        light = new DirectionalLight();     // 平行光源生成
        light.directionX = 1;               // 向き
        light.directionY = 1;               // 向き
        light.directionZ = 0.1;             // 向き
        light.color = [1.0, 1.0, 1.0];      // 色
        scene.setDirectionalLight(light);   // scene にセット
        
        // カメラ生成
        camera = new DebugCamera3D();       // カメラ生生
        camera.centerX = 0;
        camera.centerY = 9;
        camera.centerZ = -40;
        camera.distance = 90;               // 距離
        camera.theta    =-2;
        camera.update();
        //camera.enable(game.rootScene);      // ルートシーン
        scene.setCamera(camera);            // scene にセット
        
        // 床生成
        floor = new GameFloor();
        scene.addChild(floor);
        
        // プレイヤー生成
        player = new Player();
        scene.addChild(player);
        
        // 影生成
        shadow = new PlaneXZ();
        shadow.y = 0.1;
        shadow.mesh.setBaseColor([0.0, 0.0, 0.0, 1.0]);
        shadow.scale(2, 2, 2);
        shadow.mesh.texture = new Texture("texture/shadow.png");
        shadow.onenterframe = function() {
            if (player) {
                shadow.x = player.x;
                shadow.z = player.z;
            }
        };
        scene.addChild(shadow);
        
        // 敵のルートを作成
        nineleapBoxRoot = new Sprite3D();
        scene.addChild(nineleapBoxRoot);
        
        // スコア
        score = new Label();
        score.moveTo(10, 10);
        score.text      = "Distance : " + game.score + "m";
        score.color     = "white";
        score.font      = "20px 'Consolas', 'Monaco', 'MS ゴシック'";
        game.rootScene.addChild(score);
        
        
        // BGM 再生
        var bgm = new Audio("sound/bgm." + AUDIO_EXT);
        bgm.loop = true;
        bgm.volume = 0.25;
        bgm.play();
        
        // 開始処理
        game.rootScene.onenter = function() {
            game.frame = 0;
        };
        
        // 更新処理
        game.rootScene.onenterframe = function() {
            
            // レベルに応じた適生成関数を実行
            var level = Math.floor( game.frame/(game.fps*20) );
            level = Math.min(level,6);
            NineleapBoxCreateFuncTable[level]();
            
            // 衝突判定
            if (player != null) {
                for (var i=0,len=nineleapBoxRoot.childNodes.length; i<len; ++i) {
                    if (player.intersect( nineleapBoxRoot.childNodes[i] ) == true) {
                        var crash = new Crash();
                        crash.x = player.x;
                        crash.y = player.y;
                        crash.z = player.z;
                        scene.addChild(crash);
                        
                        scene.removeChild(player);
                        scene.removeChild(shadow);
                        player = null;
                        break;
                    }
                }
                
                // スコア加算
                game.score += MOVE_SPEED;
            }
        
            score.text = "Distance : " + game.score + "m";
        };
    };
    
    game.start();
};


var Player = Class.create(Sprite3D, {
    
    initialize: function()
    {
        Sprite3D.call(this);
        this.set(game.assets["model/marukichi.mqo"]);
        this.y = 1; // 位置をセット
        this.dx = 0;
        this.jump = 0;
        
        this.jumpSE = new Audio("sound/jump." + AUDIO_EXT);
        this.jumpSE.volume = 0.5;
    },
    
    onenterframe: function()
    {
        // 移動
        if (game.input.left)  this.dx -= 0.01;
        if (game.input.right) this.dx += 0.01;
        this.x += this.dx;
        
        // 安定させない
        if (this.dx == 0) { this.dx = Math.floor(Math.random()*2) ? 0.02 : -0.02; }
        
        // 制限
        if (this.x <-6.5) this.x =-6.5;
        if (this.x > 6.5) this.x = 6.5;
        
        // ジャンプ
        if (this.jump == 0 && game.input.up) {
            this.jump = 0.4;
            this.jumpSE.play();
        }
        
        // ジャンプ中の処理
        if (this.jump != 0) {
            this.jump -= 0.01;
            player.y += this.jump;
        }
        
        // 地面に着地した際の処理
        if (player.y <= 1) {
            player.y = 1;
            this.jump = 0;
        }
        
        // 向きを調整
        var angle = 180 - this.dx*300;
        angle = Math.min(angle, 270);
        angle = Math.max(angle, 90);
        mat4.identity(this.rotation);
        mat4.rotateY(this.rotation, angle*Math.PI/180);
    }
    
});


var Crash = Class.create(Sphere, {
    
    initialize: function()
    {
        Sphere.call(this);
        
        this.alpha = 1.0;
        this.mesh.setBaseColor([1.0, 0.25, 0.0, this.alpha]);
        
        // クラッシュ時の SE を再生
        var se = new Audio("sound/crash." + AUDIO_EXT);
        se.volume = 0.5;
        se.play();
    },
    
    onenterframe: function()
    {
        this.scaleX += 0.1;
        this.scaleY += 0.1;
        this.scaleZ += 0.1;
        
        this.mesh.setBaseColor([1.0, 0.25, 0.0, this.alpha]);
        
        this.alpha -= 0.0125;
        if (this.alpha < 0) {
            game.currentScene3D.removeChild(this);
            gameOver();
        }
    },
    
    ondrawbefore: function() {
        gl.enable(gl.BLEND);                // ブレンド有効化
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE); // 加算合成
        gl.disable(gl.DEPTH_TEST);          // デプスのテストを切っておく
    },
    
    ondrawafter: function() {
        gl.disable(gl.BLEND);           // ブレンド無効化
        gl.blendFunc(gl.ONE, gl.ZERO);  // デフォルトに戻す
        gl.disable(gl.DEPTH_TEST);      // デプスのテストを有効化
    },
    
});


var GameFloor = Class.create(Floor, {
    initialize: function() {
        Floor.call(this, 25, 25*10, 5, 5*5, "white", "blue");
        this.x = this.y = this.z = 0;
        
        this.offset = -80;
        this.z = this.offset;
    },
    
    onenterframe: function() {
        this.z += MOVE_SPEED;
        if (this.z >= (this.offset+20)) { this.z =this.offset; }
    }
});


var NineleapBox = Class.create(Cube, {
    
    initialize: function(x, y, z) {
        Cube.call(this);
        
        this.mesh.texture = new Texture("texture/enchant.png");
        this.mesh.texture.ambient = [0.5, 0.5, 0.5, 1.0];
        
        this.x = x;
        this.y = y;
        this.z = z;
        
        this.vy = 0.0;
        
        mat4.identity(this.rotation);
        mat4.rotateX(this.rotation, 180*Math.PI/180);
        this.scale(2, 2, 2);
        
        this.onenterframe = this.appear;
    },
    
    appear: function() {
        this.vy -= 0.01;
        this.y += this.vy;
        
        if (this.y < 1) {
            this.y = 1;
            this.onenterframe = this.move;
        }
    },
    
    move: function() {
        this.z += MOVE_SPEED;
        
        if (this.z > 50) {
            this.parentNode.removeChild(this);
        }
    }
});


var NineleapBoxRed = Class.create(NineleapBox, {
    initialize: function(x, y, z) {
        NineleapBox.call(this, x, y, z);
        
        this.mesh.setBaseColor([1.0, 0.0, 0.0, 1.0]);
        this.time = 0;
    },
    
    move: function() {
        this.x += Math.sin(this.time*3 * Math.PI/180)*0.1;
        this.z += MOVE_SPEED;
        
        if (this.z > 50) {
            this.parentNode.removeChild(this);
        }
        
        this.time += 1;
    }
});


var NineleapBoxGreen = Class.create(NineleapBox, {
    initialize: function(x, y, z) {
        NineleapBox.call(this, x, y, z);
        
        this.mesh.setBaseColor([0.0, 1.0, 0.0, 1.0]);
        this.time = 0;
    },
    
    move: function() {
        if (player) {
            this.y += (player.y-this.y)*0.1;
        }
        this.z += MOVE_SPEED;
        
        if (this.z > 50) {
            this.parentNode.removeChild(this);
        }
        
        this.time += 1;
    }
});

var NineleapBoxBlue = Class.create(NineleapBox, {
    initialize: function(x, y, z) {
        NineleapBox.call(this, x, y, z);
        
        this.mesh.setBaseColor([0.0, 0.0, 1.0, 1.0]);
        this.time = 0;
    },
    
    move: function() {
        this.z += MOVE_SPEED;
        this.z += Math.sin(this.time*4 * Math.PI/180);
        
        if (this.z > 50) {
            this.parentNode.removeChild(this);
        }
        
        this.time += 1;
    }
});


var NineleapBoxCreateFuncTable = [];

(function(){
    
    NineleapBoxCreateFuncTable[0] = function() {
        if (game.frame%30 == 0) {
            nineleapBoxRoot.addChild(new NineleapBox(Math.random()*16-8, 50, -150));
        }
    };
    
    NineleapBoxCreateFuncTable[1] = function() {
        if (game.frame%30 == 0) {
            nineleapBoxRoot.addChild(new NineleapBoxRed(Math.random()*16-8, 50, -150));
        }
    };
    
    NineleapBoxCreateFuncTable[2] = function() {
        if (game.frame%30 == 0) {
            nineleapBoxRoot.addChild(new NineleapBoxGreen(Math.random()*16-8, 50, -150));
        }
    };
    
    NineleapBoxCreateFuncTable[3] = function() {
        if (game.frame%30 == 0) {
            nineleapBoxRoot.addChild(new NineleapBoxBlue(Math.random()*16-8, 50, -150));
        }
    };
    
    NineleapBoxCreateFuncTable[4] = function() {
        if (game.frame%30 == 0) {
            var n = Math.floor(Math.random()*4);
            switch (n) {
                case 0 :
                    nineleapBoxRoot.addChild(new NineleapBox(Math.random()*16-8, 50, -150));
                    break;

                case 1 :
                    nineleapBoxRoot.addChild(new NineleapBoxRed(Math.random()*16-8, 50, -150));
                    break;

                case 2 :
                    nineleapBoxRoot.addChild(new NineleapBoxGreen(Math.random()*16-8, 50, -150));
                    break;

                case 3 :
                    nineleapBoxRoot.addChild(new NineleapBoxBlue(Math.random()*16-8, 50, -150));
                    break;
                
            }
        }
    };
    
    NineleapBoxCreateFuncTable[5] = function() {
        if (game.frame%20 == 0) {
            var n = Math.floor(Math.random()*5);
            switch (n) {
                case 0 :
                    nineleapBoxRoot.addChild(new NineleapBox(Math.random()*16-8, 50, -150));
                    break;

                case 1 :
                    nineleapBoxRoot.addChild(new NineleapBoxRed(Math.random()*16-8, 50, -150));
                    break;

                case 2 :
                    nineleapBoxRoot.addChild(new NineleapBoxGreen(Math.random()*16-8, 50, -150));
                    break;

                case 3 :
                    nineleapBoxRoot.addChild(new NineleapBoxBlue(Math.random()*16-8, 50, -150));
                    break;
            }
        }
    };
    
    NineleapBoxCreateFuncTable[6] = function() {
        if (game.frame%20 == 0) {
            var n = Math.floor(Math.random()*5);
            switch (n) {
                case 0 :
                    nineleapBoxRoot.addChild(new NineleapBox(Math.random()*16-8, 50, -150));
                    break;

                case 1 :
                    nineleapBoxRoot.addChild(new NineleapBoxRed(Math.random()*16-8, 50, -150));
                    break;

                case 2 :
                    nineleapBoxRoot.addChild(new NineleapBoxGreen(Math.random()*16-8, 50, -150));
                    break;

                case 3 :
                    nineleapBoxRoot.addChild(new NineleapBoxBlue(Math.random()*16-8, 50, -150));
                    break;

                case 4 :
                    if (Math.floor(Math.random() % 4) == 0) {
                        for (var i=0; i<8; ++i) {
                            nineleapBoxRoot.addChild(new NineleapBox(i*2-8, 50, -150));
                        }
                    }
                    break;
                
            }
        }
    };
    
})();

var TITLE_TABLE = [
    "ゆとり世代が生んだモンスター",
    "女子高校生",
    "東野幸治",
    "マクドナルドの会長",
    "Ｑちゃん",
    "間寛平"
];


var gameOver = function()
{
    var rank  = Math.floor( game.score/2000 );
    var title = TITLE_TABLE[ Math.min(rank, 5) ];
    var msg   = game.score + "m 走りました. あなたの称号は『" + title + "』です.";
    console.log(msg);
    game.end(game.score, msg);
};



// firefox のループ対応
(function(){
    
    if (BROWSER == "Firefox") {
        var onLoopFunc = function() { this.play(); };
        
        Object.defineProperty(HTMLAudioElement.prototype, "loop", {
            get: function() {
                return this._loop;
            },
            
            set: function(v) {
                // ループが false の状態で ture が来た場合ループ用関数を登録する
                if (this._loop != true && v == true) {
                    this.addEventListener("ended", onLoopFunc, false);
                }
                // 関数が登録されていて false が設定された場合ループ用関数を解除する
                else if (this._loop == true && v == false) {
                    this.removeEventListener("ended", onLoopFunc, false);
                }
                this._loop = v;
            }
        });
    }
    
})();






